
using Tao.OpenGl;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace cs5643.rigidbody
{


    /**
     * Representation of a circular bounding disk.
     *
     * @author Doug James, March 2007.
     */
    public class Disk
    {
        static int DISK_DISPLAY_LIST = -1;

        /** Center of disk. */
        public Pnt2D c { get; private set; }

        /** Radius of disk. */
        public double r { get; private set; }

        /** Fragile reference to center of Disk. */
        //Pnt2D c() { return c; }

        /** Radius of Disk. */
        //public double r() { return r; }

        /** Builds a Disk that encloses the specified blocks in their
         * frame of reference.
         * 
         * (HINT: You might get better performance from an AABB,
         * especially for text)  
         */
        public Disk(ICollection<Block> blocks)
        {
            ////////////////////////////////
            /// ;P  TEMP: LOOSE-FITTING Disk: 
            ////////////////////////////////
            /// 1. Center at average position 
            Pnt2D mean = new Pnt2D(0, 0);
            foreach (Block block in blocks)
            {
                mean.Add(block.p);
            }
            mean.Times(1.0 / (double)blocks.Count);
            c = new Pnt2D(mean);

            /// 2. FIND SMALLEST BOUNDING RADIUS FOR THIS CENTER:
            r = 0;
            foreach (Block block in blocks)
            {
                r = Math.Max(r, c.Sub(block.p).Length + 2 * block.h);//conservative block radius, 2h
            }
        }

        /** Builds Disk with specified center and radius values. */
        Disk(Pnt2D center, double radius)
        {
            c = new Pnt2D(center);
            r = radius;
        }



        /** 
         * True if point intersects this bounding volume.
         * @param p Point in frame of reference of Disk. 
         */
        public bool intersects(Pnt2D p)
        {
            Pnt2D dist = Pnt2D.Sub(p , c);
            return (dist.SquaredLength <= r * r);
        }

        /** Draws circular disk using a display list. */
        public void display()
        {
            displayDisk( c, r);
        }

        [MethodImpl(MethodImplOptions.Synchronized)]
        public static void displayDisk( Pnt2D c, double r)
        {
            if (DISK_DISPLAY_LIST == -1)
            {// MAKE DISPLAY LIST:
                int displayListIndex = Gl.glGenLists(1);
                Gl.glNewList(displayListIndex, Gl.GL_COMPILE);
                drawDisk(); /// Unit disk at origin
                Gl.glEndList();
                //Console.Out.WriteLine("MADE DISK LIST "+displayListIndex+" : "+Gl.glIsList(displayListIndex));
                DISK_DISPLAY_LIST = displayListIndex;
            }

            /// COLOR: DEFAULT WHITE
            Gl.glColor3d(1, 1, 1);

            /// DRAW ORIGIN-CIRCLE TRANSLATED TO c, and scaled by r
            Gl.glPushMatrix();
            Gl.glTranslated(c.x, c.y, 0);
            Gl.glScaled(r, r, r);
            Gl.glCallList(DISK_DISPLAY_LIST);
            Gl.glPopMatrix();
        }

        /** 
         * Draws a canonical unit disk at the origin.
         */
        private static void drawDisk()
        {
            double radius = 1;//unit
            Pnt2D p = new Pnt2D(0, 0);//origin

            double PnttorY1 = p.y;
            double PnttorX1 = p.x;

            Gl.glBegin(Gl.GL_TRIANGLES);
            int N = 20; //45;
            for (int i = 0; i <= N; i++)
            {
                double angle = ((double)i) * 2.0 * Math.PI / (double)N;
                double PnttorX = p.x + radius * Math.Sin(angle);
                double PnttorY = p.y + radius * Math.Cos(angle);
                Gl.glVertex3d((float)p.x, (float)p.y, 0);
                Gl.glVertex3d((float)PnttorX1, (float)PnttorY1, 0);
                Gl.glVertex3d((float)PnttorX, (float)PnttorY, 0);
                PnttorY1 = PnttorY;
                PnttorX1 = PnttorX;
            }
            Gl.glEnd();
        }




    }
}